﻿using System;
using System.Collections.Generic;
using JetBrains.Annotations;
using JetBrains.Util;

namespace GammaJul.ReSharper.GammaXaml {

	/// <summary>
	/// Contains extension methods related to collections.
	/// </summary>
	public static class CollectionExtensions {
		
		/// <summary>
		/// Projects each element of a list immediatly into a new form, into a resulting array.
		/// </summary>
		/// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam>
		/// <typeparam name="TResult">The type of the value returned by <paramref name="selector"/>.</typeparam>
		/// <param name="source">A list of values to invoke a transform function on.</param>
		/// <param name="selector">A transform function to apply to each element.</param>
		/// <returns>An array whose elements are the result of invoking the transform function on each element of <paramref name="source"/>.</returns>
		/// <remarks>Using this method is more performant that calling <c>Select().ToArray()</c> on a list.</remarks>
		[NotNull]
		public static TResult[] SelectToArray<TSource, TResult>([NotNull] this IList<TSource> source, [NotNull] Func<TSource, TResult> selector) {
			if (source == null)
				throw new ArgumentNullException("source");
			if (selector == null)
				throw new ArgumentNullException("selector");

			int count = source.Count;
			if (count == 0)
				return EmptyArray<TResult>.Instance;

			var result = new TResult[count];
			for (int i = 0; i < count; ++i)
				result[i] = selector(source[i]);
			return result;
		}

		/// <summary>
		/// Wraps a <see cref="IList{T}"/> in a <see cref="ReadOnlyList{T}"/>.
		/// </summary>
		/// <typeparam name="T">The type of elements in the list.</typeparam>
		/// <param name="list">The list that will be made read-only.</param>
		/// <returns>A <see cref="ReadOnlyList{T}"/> wrapper around <paramref name="list"/>.</returns>
		[NotNull]
		public static ReadOnlyList<T> AsReadOnly<T>([NotNull] this IList<T> list) {
			return new ReadOnlyList<T>(list);
		}

	}

}